package componentes.basicos;

/**
 * Classe para a representação de um barramento de dados. 
 * Esta classe pode representar um tipo de barramento e é usada para
 * realizar as conexões entre os elementos de estados.
 * 
 * @author Gustavo Miguel, Cleisson Alves, Evandro Francisco, Lucas.
 */
public class Barramento {
    
    private Palavra bits;       // Palavra para indicar os bits de um barramento.
    private final int tamanho;  // Atributo para indicar o tamanho de um barramento.
    
    /**
     * Cria um Barramento padrão. Um barramento padrão possui 32 bits, onde 
     * todos eles são iguais a zero.
     * @ see Palavra.
     */
    public Barramento () {
        bits = new Palavra();
        tamanho = 32;
    }
    
    // Construtor da Classe
    /**
     * Cria um barramento simples com um tamanho especificado.
     * @param tamanho Tamanho do Barramtno.
     */
    public Barramento (int tamanho){
        this.tamanho = tamanho;
    }
    
    /**
     * Cria um barramento simples com bits.
     * @param bits bits composto pelo Barramento.
     * @exception Bits invalidos para o Barramento.
     */
    public Barramento(Palavra bits) {
        if(bits.equals(null)) {
            tamanho = 0;
        } else if(!bits.verificaPalavra()){
            throw new IllegalArgumentException("String de Bits Invalida!");

        } else {
            this.bits = bits;
            tamanho = bits.tamanhoPalavra();
        }
    }

    /**
     * Retorna o tamanho de um barramento.
     * @return Tamanho de um barramento.
     */
    public int getTamanho() {
        return tamanho;
    }

    /**
     * Retorna os bits contidos no barramento.
     * @return Bits contido no Barramento.
     */
    public String getBits() {
        return bits.getPalavra();
    }
    
    public Palavra getPalavra() {
        return bits;
    }

    /**
     * Configura os bits em um barramento
     * @param bits Nova String de bits a ser configurada.
     * @exception Bits inválidos para o Barramento.
     */
    public void setBits(Palavra p) {
        if(p.verificaPalavra() && p.tamanhoPalavra()==tamanho){
            this.bits = p;
        }else{
            throw new IllegalArgumentException("String de Bits Invalida!");
        }
    }
    
    public void setBitsValor(int valor) {
        
        String valorEmString = Integer.toBinaryString(valor);
        int limite = 32 - valorEmString.length();
        for(int i = 0; i < limite; ++i) {
            valorEmString = "0".concat(valorEmString);
        }
        setBits(new Palavra(valorEmString));
    }
    
    /**
     * Retorna uma cadeia de bits que se extende desde os parâmetros inicio e fim.
     * @param inicio valor inteiro do início da cadeia de bits.
     * @param fim valor inteiro do fim da cadeia de bits.
     * @return Uma cadeia de bits contida no intervalo [inicio, fim].
     */
    public String getSubBits(int inicio, int fim) {
        
        return getBits().substring(inicio, fim);
    }
    /**
     * Retorna os bits de um barramento na forma de valores inteiros. 
     * @return Bits na forma inteira.
     */
    public int getBitsValor(){        
        if(getBits().charAt(0) == '1') {
            return -Integer.parseInt(ALU.complemento2(getBits()),2);
        }
        return Integer.parseInt(getBits(),2);
    }
    
    /**
     * Retorna uma cadeia de bits que se extende desde os parâmetros inicio e fim
     * na forma de valores inteiros.
     * @param inicio valor inteiro do início da cadeia de bits.
     * @param fim valor inteiro do fim da cadeia de bits.
     * @return Cadeia de bits na forma inteira contida no intervalo [inicio, fim].
     */
    public int getSubBitsValor(int begin, int end){
        return Integer.parseInt(getSubBits(begin, end),2);
    }

} // Fim da classe
